export class DateUtil {
  /**
   * 格式化日期为指定格式
   * @param date 日期对象或时间戳
   * @param format 格式模板，如 'YYYY-MM-DD HH:mm:ss'
   */
  static format(date: Date | number, format = "YYYY-MM-DD HH:mm:ss"): string {
    const d = typeof date === "number" ? new Date(date) : date;

    const pad = (n: number) => n.toString().padStart(2, "0");

    return format
      .replace(/YYYY/, d.getFullYear().toString())
      .replace(/MM/, pad(d.getMonth() + 1))
      .replace(/DD/, pad(d.getDate()))
      .replace(/HH/, pad(d.getHours()))
      .replace(/mm/, pad(d.getMinutes()))
      .replace(/ss/, pad(d.getSeconds()));
  }

  /**
   * 增加/减少天数
   * @param date 日期
   * @param days 正数为加，负数为减
   */
  static addDays(date: Date, days: number): Date {
    const result = new Date(date);
    result.setDate(result.getDate() + days);
    return result;
  }

  /**
   * 获取两个日期之间的天数差
   */
  static diffDays(start: Date, end: Date): number {
    const msPerDay = 1000 * 60 * 60 * 24;
    return Math.floor((end.getTime() - start.getTime()) / msPerDay);
  }

  /**
   * 计算两个日期之间的差距，并以人类可读的形式返回：
   * - 小于1小时：返回“差了 X 分钟”
   * - 小于1天：返回“差了 X 小时”
   * - 小于1月：返回“差了 X 天”
   * - 小于1年：返回“差了 X 个月”
   * - 超过1年：返回“差了 X 年”
   *
   * @param date1 第一个日期，可以是字符串或 Date 对象
   * @param date2 第二个日期，可以是字符串或 Date 对象
   * @returns 描述两个日期差距的字符串（单位为分钟、小时、天、月或年）
   */
  static getTimeDiffDesc(date1: string | Date, date2: string | Date): string {
    const d1 = new Date(date1);
    const d2 = new Date(date2);
    const diffMs = Math.abs(d1.getTime() - d2.getTime());

    const minute = 60 * 1000;
    const hour = 60 * minute;
    const day = 24 * hour;
    const month = 30 * day;
    const year = 365 * day;

    if (diffMs < hour) {
      const mins = Math.floor(diffMs / minute);
      return `${mins}分钟前`;
    } else if (diffMs < day) {
      const hours = Math.floor(diffMs / hour);
      return `${hours}小时前`;
    } else if (diffMs < month) {
      const days = Math.floor(diffMs / day);
      return `${days}天前`;
    } else if (diffMs < year) {
      const months = Math.floor(diffMs / month);
      return `${months}个月前`;
    } else {
      const years = Math.floor(diffMs / year);
      return `${years}年前`;
    }
  }

  /**
   * 获取某月最后一天
   * @param year 年份
   * @param month 月份（1-12）
   */
  static getLastDayOfMonth(year: number, month: number): number {
    return new Date(year, month, 0).getDate();
  }

  /**
   * 获取星期几（返回中文）
   * @param date 日期
   */
  static getDayOfWeek(date: Date): string {
    const days = [
      "星期日",
      "星期一",
      "星期二",
      "星期三",
      "星期四",
      "星期五",
      "星期六",
    ];
    return days[date.getDay()];
  }

  /**
   * 是否为闰年
   * @param year 年份
   */
  static isLeapYear(year: number): boolean {
    return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
  }

  /**
   * 通过正则表达式快速提取并格式化日期为 "· M-D" 格式
   * @param {string} inputDate - 标准日期字符串，格式必须为 "YYYY-MM-DD HH:mm:ss"
   * @returns {string} 格式化后的简短日期字符串（如 "· 4-5"）
   * @throws {Error} 如果输入格式不匹配，可能返回意外结果
   * @example
   * formatDateToShortRegex("2025-04-05 15:22:52"); // 返回 "· 4-5"
   */
  static formatDateToShort(inputDate: string): string {
    const match = inputDate.match(/^(\d{4})-(\d{2})-(\d{2})/);
    if (!match) {
      throw new Error("输入格式错误，必须为 'YYYY-MM-DD HH:mm:ss'");
    }

    const [, year, month, day] =
      inputDate.match(/^(\d{4})-(\d{2})-(\d{2})/) || [];
    return `· ${parseInt(month, 10)}-${parseInt(day, 10)}`;
  }

  static convertSecondsToHMS(seconds) {
    var hours = Math.floor(seconds / 3600);
    var minutes = Math.floor((seconds % 3600) / 60);
    var remainingSeconds = seconds % 60;

    return hours + ":" + minutes + ":" + remainingSeconds;
  }

  /**
   * 将秒数格式化为 MM:SS 或 HH:MM:SS 格式
   * @param seconds 秒数，支持 number 或字符串（可转为数字）
   * @returns 格式化时间字符串
   */
  static formatTime(seconds: number | string): string {
    let totalSeconds = Number(seconds);
    if (isNaN(totalSeconds) || totalSeconds < 0) totalSeconds = 0;

    const hours = Math.floor(totalSeconds / 3600);
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const secs = Math.floor(totalSeconds % 60);

    const pad = (n: number) => n.toString().padStart(2, "0");

    if (hours > 0) {
      return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
    } else {
      return `${pad(minutes)}:${pad(secs)}`;
    }
  }
}
